package com.laker.autotest.common.reporters;

import com.laker.autotest.common.utils.TestNGUtil;
import org.testng.*;
import org.testng.xml.XmlSuite;

import java.io.File;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * 现代简约风格的邮件HTML测试报告生成器
 *
 * <p>设计特点：
 * <ul>
 *   <li>内联样式，适合邮件客户端展示</li>
 *   <li>现代卡片式布局和渐变配色</li>
 *   <li>清晰的统计数据和状态展示</li>
 *   <li>纯HTML/CSS实现，无外部依赖</li>
 *   <li>轻量级设计，适合邮件传输</li>
 * </ul>
 *
 * @author laker
 */
public class EasyHtmlEmailReporter implements IReporter {
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
        try {
            String reportDir = TestNGUtil.getReportDir();
            File dir = new File(reportDir);
            if (!dir.exists()) dir.mkdirs();
            File reportFile = new File(dir, TestNGUtil.getReportFileName());
            try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(reportFile.toPath()), StandardCharsets.UTF_8))) {
                writer.println("<!DOCTYPE html><html><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width,initial-scale=1.0'><title>测试报告</title>");
                writer.println("<style>*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);padding:20px;color:#2d3748}.container{max-width:1000px;margin:0 auto}.header{background:#fff;border-radius:12px;padding:24px;margin-bottom:16px;box-shadow:0 4px 12px rgba(0,0,0,0.1)}.header h1{font-size:24px;font-weight:600;color:#1a202c;margin-bottom:8px}.timestamp{color:#718096;font-size:14px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:16px}.stat-card{background:#fff;border-radius:10px;padding:20px;text-align:center;box-shadow:0 2px 8px rgba(0,0,0,0.05)}.stat-label{font-size:12px;color:#718096;margin-bottom:8px;font-weight:500}.stat-value{font-size:32px;font-weight:700}.stat-card.total .stat-value{color:#667eea}.stat-card.passed .stat-value{color:#48bb78}.stat-card.failed .stat-value{color:#f56565}.stat-card.skipped .stat-value{color:#ed8936}.results{background:#fff;border-radius:12px;padding:24px;box-shadow:0 4px 12px rgba(0,0,0,0.1)}table{width:100%;border-collapse:separate;border-spacing:0;font-size:14px}th{text-align:left;padding:12px 16px;background:#f7fafc;font-weight:600;color:#4a5568;border-bottom:2px solid #e2e8f0;font-size:12px;text-transform:uppercase}td{padding:12px 16px;border-bottom:1px solid #f1f5f9}tr:hover{background:#f8fafc}.status-badge{display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:600}.status-badge.passed{background:#c6f6d5;color:#22543d}.status-badge.failed{background:#fed7d7;color:#742a2a}.status-badge.skipped{background:#feebc8;color:#7c2d12}.error-msg{margin-top:8px;padding:12px;background:#fff5f5;border-left:3px solid #fc8181;border-radius:4px;font-family:Monaco,Menlo,Consolas,monospace;font-size:11px;color:#742a2a;max-height:150px;overflow-y:auto;white-space:pre-wrap;word-break:break-word}.footer{text-align:center;color:#fff;font-size:14px;margin-top:20px;opacity:0.8}</style></head><body><div class='container'>");
                writer.println("<div class='header'><h1>测试报告</h1><div class='timestamp'>" + DATE_FORMAT.format(new Date()) + "</div></div>");
                // 汇总统计
                int totalPassed = 0, totalFailed = 0, totalSkipped = 0, total = 0;
                for (ISuite suite : suites) {
                    for (ISuiteResult result : suite.getResults().values()) {
                        ITestContext ctx = result.getTestContext();
                        totalPassed += ctx.getPassedTests().size();
                        totalFailed += ctx.getFailedTests().size();
                        totalSkipped += ctx.getSkippedTests().size();
                    }
                }
                total = totalPassed + totalFailed + totalSkipped;
                writer.println("<div class='stats'>");
                writer.println("<div class='stat-card total'><div class='stat-label'>总用例数</div><div class='stat-value'>" + total + "</div></div>");
                writer.println("<div class='stat-card passed'><div class='stat-label'>通过</div><div class='stat-value'>" + totalPassed + "</div></div>");
                writer.println("<div class='stat-card failed'><div class='stat-label'>失败</div><div class='stat-value'>" + totalFailed + "</div></div>");
                writer.println("<div class='stat-card skipped'><div class='stat-label'>跳过</div><div class='stat-value'>" + totalSkipped + "</div></div>");
                writer.println("</div>");
                // 详细用例
                writer.println("<div class='results'><table><tr><th>测试用例</th><th>状态</th><th>开始时间</th><th>耗时</th><th>错误信息</th></tr>");
                for (ISuite suite : suites) {
                    for (ISuiteResult result : suite.getResults().values()) {
                        ITestContext ctx = result.getTestContext();
                        List<ITestResult> allResults = new ArrayList<>();
                        allResults.addAll(ctx.getPassedTests().getAllResults());
                        allResults.addAll(ctx.getFailedTests().getAllResults());
                        allResults.addAll(ctx.getSkippedTests().getAllResults());
                        allResults.sort(Comparator.comparingLong(ITestResult::getStartMillis));
                        for (ITestResult res : allResults) {
                            String classMethod = res.getTestClass().getRealClass().getSimpleName() + "." + res.getMethod().getMethodName();
                            String status = getStatusText(res);
                            String statusClass = getStatusClass(res);
                            String startTime = DATE_FORMAT.format(new Date(res.getStartMillis()));
                            long duration = res.getEndMillis() - res.getStartMillis();
                            String formattedDuration = formatDuration(duration);
                            String exception = getExceptionMessage(res);
                            writer.print("<tr>");
                            writer.print("<td>" + classMethod + "</td>");
                            writer.print("<td><span class='status-badge " + statusClass + "'>" + status + "</span></td>");
                            writer.print("<td>" + startTime + "</td>");
                            writer.print("<td>" + formattedDuration + "</td>");
                            writer.print("<td>" + (exception == null ? "<span style='color:#a0aec0'>-</span>" : "<div class='error-msg'>" + escapeHtml(exception) + "</div>") + "</td>");
                            writer.println("</tr>");
                        }
                    }
                }
                writer.println("</table></div><div class='footer'>Laker AutoTest Framework &copy; 2025</div></div></body></html>");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getStatusText(ITestResult result) {
        switch (result.getStatus()) {
            case ITestResult.SUCCESS:
                return "通过";
            case ITestResult.FAILURE:
                return "失败";
            case ITestResult.SKIP:
                return "跳过";
            default:
                return "未知";
        }
    }

    private String getStatusClass(ITestResult result) {
        switch (result.getStatus()) {
            case ITestResult.SUCCESS:
                return "passed";
            case ITestResult.FAILURE:
                return "failed";
            case ITestResult.SKIP:
                return "skipped";
            default:
                return "";
        }
    }

    private String getExceptionMessage(ITestResult result) {
        Throwable t = result.getThrowable();
        if (t != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            t.printStackTrace(pw);
            return sw.toString();
        }
        return null;
    }

    private String escapeHtml(String text) {
        if (text == null) return "";
        return text.replace("&", "&amp;")
                   .replace("<", "&lt;")
                   .replace(">", "&gt;")
                   .replace("\"", "&quot;")
                   .replace("'", "&#x27;");
    }

    /**
     * 智能格式化时间，自动转换为易读的单位
     * @param ms 毫秒数
     * @return 格式化后的时间字符串
     */
    private String formatDuration(long ms) {
        if (ms < 1000) {
            return ms + "ms";
        } else if (ms < 60000) {
            double seconds = ms / 1000.0;
            return String.format("%.2fs", seconds);
        } else if (ms < 3600000) {
            long minutes = ms / 60000;
            long seconds = (ms % 60000) / 1000;
            return minutes + "m " + seconds + "s";
        } else {
            long hours = ms / 3600000;
            long minutes = (ms % 3600000) / 60000;
            long seconds = (ms % 60000) / 1000;
            return hours + "h " + minutes + "m " + seconds + "s";
        }
    }
}

